/*
 *  levelUpGame - CollisionHandler.cpp
 *  Copyright 2011 W. Reckman. All rights reserved.
 */
#include <string>
#include "Settings.h"
#include "GameModel.h"
#include "LevelUpApp.h"
#include "CollisionHandler.h"

using std::string;


//--------------------------------------------------------------
CollisionHandler::CollisionHandler( LevelUpApp& appRef_ )
: appRef( appRef_ ), game( appRef_.getGame() ), s( Settings::getInstance() )
{}

//--------------------------------------------------------------
void CollisionHandler::setup() {
	playerFreezeTime = ofToFloat( *s.getValueInGroup( "player_eaten_freeze_time", "game", "1" ) );
}


//--------------------------------------------------------------
void CollisionHandler::onCollisionDetected( EventArgsCollision& ev_ ) {
	//logCollisionEvent( ev_ );
	
	//swap events if the second one is a player but hte first one is not (to make checks easier)
	if ( ev_.co1Type != EventArgsCollision::COT_PLAYER && ev_.co2Type == EventArgsCollision::COT_PLAYER ) {
		Pickup* puSwap;
		Ghost* ghSwap;
		switch ( ev_.co1Type ) {
			case EventArgsCollision::COT_PICKUP:
				puSwap = ev_.o1.pickup;
				ev_.o1.player = ev_.o2.player;
				ev_.o2.pickup = puSwap;
				break;
			case EventArgsCollision::COT_GHOST:
				ghSwap = ev_.o1.ghost;
				ev_.o1.player = ev_.o2.player;
				ev_.o2.ghost = ghSwap;
				break;
		}
		ev_.co2Type = ev_.co1Type;
		ev_.co1Type = EventArgsCollision::COT_PLAYER;
	}
	
	if ( ev_.co1Type == EventArgsCollision::COT_PLAYER && ev_.co2Type == EventArgsCollision::COT_PLAYER ) {
		handlePlayerPlayerCollision( ev_.o1.player, ev_.o2.player );
	} else if ( ( ev_.co1Type == EventArgsCollision::COT_PLAYER && ev_.co2Type == EventArgsCollision::COT_PICKUP ) ) {
		handlePlayerPickupCollision( ev_.o1.player, ev_.o2.pickup );
	} else if ( ( ev_.co1Type == EventArgsCollision::COT_PLAYER && ev_.co2Type == EventArgsCollision::COT_GHOST ) ) {
		handlePlayerGhostCollision( ev_.o1.player, ev_.o2.ghost );
	}
}

/*********************
 * PRIVATE FUNCTIONS *
 *********************/

//--------------------------------------------------------------
void CollisionHandler::handlePlayerPlayerCollision( Player* p1, Player* p2 ) {
	ofPoint p1Pos( p1->getPosition().x, p1->getPosition().y );
	ofPoint p2Pos( p2->getPosition().x, p2->getPosition().y );
	DIRECTION p1Dir = p1->getDirection(), p2Dir = p2->getDirection();
	DIRECTION p1CDir = getVectorOrientation( p1Pos, p2Pos ), p2CDir = getVectorOrientation( p2Pos, p1Pos );
	
	ofPoint p12v = p2Pos - p1Pos;
	float p12a = atan2f( p12v.y, p12v.x ) * ( 360.0 / ( 2 * PI ) );
	if ( p12a < 0.0f ) p12a += 360;
	ofPoint p21v = p1Pos - p2Pos;
	float p21a = atan2f( p21v.y, p21v.x ) * ( 360.0 / ( 2 * PI ) );
	if ( p21a < 0.0f ) p21a += 360;
	
	if ( p1->getDirection() == getVectorOrientation( p1Pos, p2Pos ) ) {
		p1->revert();
		p1->setDirection( D_STOP, true );
	}
	
	if ( p2->getDirection() == getVectorOrientation( p2Pos, p1Pos ) ) {
		p2->revert();
		p2->setDirection( D_STOP, true );
	}
	
	game.p0Colliding = true; //TEMP
}

//--------------------------------------------------------------
void CollisionHandler::handlePlayerPickupCollision( Player* player, Pickup* pickup ) {
	GameController& gCtl = appRef.getGameController();
	AudioController& aCtl = appRef.getAudioController();
	BALANCE_KIND bt = pickup->getBalanceType();
	
	AudioController::SOUNDS sndType = ( bt == BK_CULTURE ) ? AudioController::SND_PICKUP_CULTURE : AudioController::SND_PICKUP_INDUSTRY;
	aCtl.setPan( sndType, game.getPanPosition( pickup->getPosition().x ) );
	aCtl.play( sndType );
	
	//TODO: increment goodPickup/badPickup on player
	int puSide = ( bt == BK_CULTURE ) ? -1 : 1;
	float ptb = player->getTargetBalance().getBalanceFloat();
	float gb = game.getBalanceMeter().getBalanceFloat();
	if ( ( ptb < gb && puSide == -1 ) || ptb > gb && puSide == 1 ) {
		player->incrementGoodPickupCount();
	} else {
		player->incrementBadPickupCount();
	}
	
	game.addBalance( game.getBalanceStepGlobal(), bt );
	player->addBalance( game.getBalanceStepPlayer(), bt );
	gCtl.sendBalanceChangedEvent();
	
	pickup->setState( Pickup::PST_DESTROY_ANIM );
	game.p0Colliding = true; //TEMP
}

//--------------------------------------------------------------
void CollisionHandler::handlePlayerGhostCollision( Player* player, Ghost* ghost ) {
	AudioController& audioCtl = appRef.getAudioController();
	
	audioCtl.setLoop( AudioController::SND_IDLE, true );
	audioCtl.setPan( AudioController::SND_IDLE, game.getPanPosition( player->getPosition().x ) );
	audioCtl.play( AudioController::SND_IDLE );
	
	audioCtl.setPan( AudioController::SND_DIE, game.getPanPosition( player->getPosition().x ) );
	audioCtl.play( AudioController::SND_DIE );
	
	player->setBlocked( true );
	player->setCollidable( false );
	player->startFreezeTimeout( playerFreezeTime );
}


//--------------------------------------------------------------
void CollisionHandler::logCollisionEvent( EventArgsCollision& ev_ ) {
	static const string ghostText = "ghost", playerText = "player", pickupText = "pickup";
	
	const string& on1 = ( ev_.co1Type == EventArgsCollision::COT_PLAYER )
		? playerText
		: ( ev_.co1Type == EventArgsCollision::COT_GHOST ) ? ghostText : pickupText;
	
	const string& on2 = ( ev_.co2Type == EventArgsCollision::COT_PLAYER )
		? playerText
		: ( ev_.co1Type == EventArgsCollision::COT_GHOST ) ? ghostText : pickupText;
	
	ofLog( OF_LOG_NOTICE, "received collision event between %s and %s", on1.c_str(), on2.c_str() );
}
